﻿namespace EasyWeb.Test
{
    using System;
    using System.Dynamic;
    using System.Linq.Expressions;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class EWHelpers_ExpressionHelpers_Test
    {
        [TestMethod]
        public void Lambda_Test()
        {
            string id;

            id = CreateFunction<PlainObjects.Order>("Id", false)(new PlainObjects.Order() { Id = "AAA" });
            Assert.AreEqual("AAA", id);

            id = CreateFunction<SimpleObjects.Order>("Key.Id", false)(new SimpleObjects.Order()
            {
                Key = new SimpleObjects.OrderKey() { Id = "AAA" }
            });
            Assert.AreEqual("AAA", id);

            id = CreateFunction<ComplexObjects.Order>("Id.OrderId", false)(new ComplexObjects.Order()
            {
                Id = new ComplexObjects.OrderKey() { OrderId = "AAA" }
            });
            Assert.AreEqual("AAA", id);
        }

        [TestMethod]
        public void Lambda_Anonymous_Test()
        {
            dynamic obj;
            string id;

            obj = new { Id = "AAA" };
            id = (string)CreateFunction(obj.GetType(), "Id", false).DynamicInvoke(obj);
            Assert.AreEqual("AAA", id);

            obj = new { Key = new { Id = "AAA" } };
            id = (string)CreateFunction(obj.GetType(), "Key.Id", false).DynamicInvoke(obj);
            Assert.AreEqual("AAA", id);
        }

        [TestMethod]
        public void Lambda_Dynamic_Test()
        {
            dynamic obj;
            string id;

            obj = new ExpandoObject();
            obj.Id = "AAA";
            id = (string)CreateFunction(obj.GetType(), "Id", false).DynamicInvoke(obj);
            Assert.AreEqual("AAA", id);

            obj = new ExpandoObject();
            obj.Key = new ExpandoObject();
            obj.Key.Id = "AAA";
            id = (string)CreateFunction(obj.GetType(), "Key.Id", false).DynamicInvoke(obj);
            Assert.AreEqual("AAA", id);
        }

        [TestMethod]
        public void Lambda_Null_Test()
        {
            string id;

            id = CreateFunction<PlainObjects.Order>("Id", true)(new PlainObjects.Order());
            Assert.IsNull(id);

            id = CreateFunction<SimpleObjects.Order>("Key.Id", true)(new SimpleObjects.Order());
            Assert.IsNull(id);

            id = CreateFunction<ComplexObjects.Order>("Id.OrderId", true)(new ComplexObjects.Order());
            Assert.IsNull(id);
        }

        private static Func<T, string> CreateFunction<T>(string memberPath, bool allowNull)
        {
            var expression = (Expression<Func<T, string>>)EWHelpers.ExpressionHelpers.Lambda(typeof(T), memberPath, allowNull);
            return expression.Compile();
        }

        private static Delegate CreateFunction(Type type, string memberPath, bool allowNull)
        {
            var expression = EWHelpers.ExpressionHelpers.Lambda(type, memberPath, allowNull);
            return expression.Compile();
        }

        public static class PlainObjects
        {
            public class Order
            {
                public string Id { get; set; }
            }
        }

        public static class SimpleObjects
        {
            public class Order
            {
                public OrderKey Key { get; set; }
            }

            public class OrderKey
            {
                public string Id { get; set; }
            }
        }

        public static class ComplexObjects
        {
            public abstract class DomainObject<T, TId>
            {
                public TId Id { get; set; }
            }

            public class Order : DomainObject<Order, OrderKey>
            {
            }

            public class OrderKey
            {
                public string OrderId { get; set; }
            }
        }
    }
}
